package com.gitee.feizns.itrip.personal.auth.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.gitee.feizns.itrip.personal.auth.service.exception.ActivationException;
import com.gitee.feizns.itrip.personal.auth.service.exception.UserException;
import com.gitee.feizns.itrip.personal.beans.pojo.User;
import com.gitee.feizns.itrip.personal.mapper.UserMapper;
import com.gitee.feizns.itrip.personal.utils.service.AbstractService;
import com.gitee.feizns.itrip.personal.auth.service.RegisterService;
import com.gitee.feizns.itrip.personal.utils.service.EmailService;
import com.gitee.feizns.itrip.personal.utils.service.PhoneService;
import com.gitee.feizns.itrip.personal.utils.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Date;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import static com.gitee.feizns.itrip.personal.auth.service.exception.ActivationException.ACTIVATION_CODE_DOES_NOT_EXIST;
import static com.gitee.feizns.itrip.personal.auth.service.exception.ActivationException.ACTIVATION_CODE_HAS_EXPIRED;
import static com.gitee.feizns.itrip.personal.mapper.UserMapper.ACTIVATED;
import static com.gitee.feizns.itrip.personal.mapper.UserMapper.INACTIVATED;
import static com.gitee.feizns.itrip.personal.utils.service.exception.ServiceException.VALIDATE_ERROR;

/**
 * @author feizns
 * @since 2018/12/26 0026
 */
@Service
public class RegisterServiceImpl extends AbstractService<User, UserMapper> implements RegisterService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private EmailService emailService;

    @Autowired
    private PhoneService phoneService;

    @Override
    public boolean add(User entity) {
        entity.setCreationDate(new Date(System.currentTimeMillis()));
        entity.setActivated(INACTIVATED);
        if( entity.getUserPassword() != null )
            entity.setUserPassword(Utils.getMD5(entity.getUserPassword()));
        return super.add(entity);
    }

    @Override
    public boolean availableUserName(String userName) {
        return baseMapper.selectCount(new EntityWrapper<User>().and(" userName = {0} ", userName)) == 0;
    }

    @Override
    public boolean availableUserCode(String userCode) {
        return baseMapper.selectCount(new EntityWrapper<User>().and(" userCode = {0} ", userCode)) == 0;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void emailRegister(User user) {
        String emailVal = Utils.getUUIDCode();
        register(DEFAULT_REDIS_EMAIL_PREFIX, "该邮箱用户已注册.", user, (redisKey) -> {
            redisTemplate.opsForValue().set(redisKey, emailVal, DEFAULT_EMAIL_EXISTS_TIME, TimeUnit.MINUTES);
        });
        emailService.send(user.getUserCode(), emailVal);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void phoneRegister(User entity) {
        String phoneVal = Utils.getNumber(DEFAULT_PHONE_CODE_NUMBER);
        register(DEFAULT_REDIS_PHONE_PREFIX, "该手机用户已注册.", entity, (redisKey) -> {
            redisTemplate.opsForValue().set(redisKey, phoneVal, DEFAULT_PHONE_EXISTS_TIME, TimeUnit.MINUTES);
        });
        phoneService.send(entity.getUserCode(), phoneVal);
    }

    private void register(String prefix, String errorInfo, User entity, Consumer<String> send) {
        if( availableUserCode(entity.getUserCode()) == false )
            throw new UserException(VALIDATE_ERROR, errorInfo);

        String redisKey = prefix + entity.getUserCode();

        send.accept(redisKey);

        entity.setUserType(UserMapper.SELF_USER_TYPE);

        add(entity);
    }

    @Override
    public void emailActivated(String userCode, String code) {
        active(DEFAULT_REDIS_EMAIL_PREFIX, userCode, code);
    }

    @Override
    public void phoneActivated(String userCode, String code) {
        active(DEFAULT_REDIS_PHONE_PREFIX, userCode, code);
    }

    private void active(String prefix, String userCode, String code) {
        String redisKey = prefix + userCode;
        String val = redisTemplate.opsForValue().get(redisKey);
        if( val == null )
            throw new ActivationException(ACTIVATION_CODE_HAS_EXPIRED, "激活码已过期.");

        if( val.equals(code) == false )
            throw new ActivationException(ACTIVATION_CODE_DOES_NOT_EXIST, "激活码错误.");

        baseMapper.update(new User().setActivated(UserMapper.ACTIVATED), new EntityWrapper<User>().and(" userCode = {0} ", userCode));
        redisTemplate.delete(redisKey);
    }

    @Override
    public boolean isActivated(String userCode) {
        return baseMapper.selectCount(
                new EntityWrapper<User>()
                        .and(" userCode = {0} and activated = {1} ", userCode, ACTIVATED)) == 1;
    }

}